package interview.i_003_concurrent;

import org.junit.jupiter.api.Test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 要求用线程顺序打印 A1B2C3....Z26
 * 保证 t2 在 t1 之前打印，也就是说保证首先输出的是 A 而不是 1，这个时候该如何做？
 */
class T006_OrderPrint {
    char[] aI = "1234567".toCharArray();
    char[] aC = "ABCDEFG".toCharArray();
    final Object lock = new Object();

    @Test
    void demo1() { // 无法保证 t1、t2 的先后顺序
        new Thread(() -> {
            synchronized (lock) {
                for (char c : aI) {
                    try {
                        lock.notify();
                        lock.wait(); // 让出锁
                        System.out.print(c);
                    } catch (InterruptedException ignored) {
                    }
                }
                lock.notify(); // 必须，否则无法停止程序
            }
        }).start();
        new Thread(() -> {
            synchronized (lock) {
                for (char c : aC) {
                    try {
                        System.out.print(c);
                        lock.notify();
                        lock.wait();
                    } catch (InterruptedException ignored) {
                    }
                }
                lock.notify();
            }
        }).start();
    }

    volatile boolean status = false;

    @Test
    void demo2() {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        new Thread(() -> {
            try {
                lock.lock();
                status = true;
                for (char c : aI) {
                    condition.await();
                    System.out.print(c);
                    condition.signal();
                }
            } catch (Exception ignored) {
            } finally {
                lock.unlock();
            }
        }).start();
        new Thread(() -> {
            try {
                while (!status) {
                }
                lock.lock();
                for (char c : aC) {
                    System.out.print(c);
                    condition.signal();
                    condition.await();
                }
            } catch (Exception ignored) {
            } finally {
                lock.unlock();
            }
        }).start();
    }

    @Test
    void demo3() { // 无法保证 t1、t2 的先后顺序
        Lock lock = new ReentrantLock();
        Condition conditionT1 = lock.newCondition(); // Condition 本质是锁资源上不同的等待队列
        Condition conditionT2 = lock.newCondition();
        new Thread(() -> {
            try {
                lock.lock();
                for (char c : aI) {
                    System.out.print(c);
                    conditionT2.signal();
                    conditionT1.await();
                }
                conditionT2.signal();
            } catch (Exception ignored) {
            } finally {
                lock.unlock();
            }
        }).start();
        new Thread(() -> {
            try {
                lock.lock();
                for (char c : aC) {
                    System.out.print(c);
                    conditionT1.signal();
                    conditionT2.await();
                }
                conditionT1.signal();
            } catch (Exception ignored) {
            } finally {
                lock.unlock();
            }
        }).start();
    }
}